package com.sxs.aspectj;

import com.sxs.annotation.RateLimit;
import com.sxs.enums.LimitType;
import com.sxs.utils.IpUtils;
import com.sxs.utils.ServletUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect //告诉框架我是一个切面类
@Component// 随着框架的启动而启动
@Slf4j
@AllArgsConstructor
public class RateLimitAspect2 {

    private final RedisTemplate<Object, Object> redisTemplate;

    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
        // 组合限流 key
        String limitKey = getLimitKey(point, rateLimit);
        // 执行限流逻辑
        boolean limited = isLimited(limitKey, rateLimit.time(), rateLimit.count());
        if (limited) {
            throw new RuntimeException(rateLimit.message());
        }
        // 执行目标方法
        return point.proceed();
    }


    private String getLimitKey(ProceedingJoinPoint point, RateLimit rateLimit) {
        StringBuilder sb = new StringBuilder(rateLimit.key());
        // 获取请求的类名
        String className = point.getTarget().getClass().getName();
        // 获取请求的方法名
        String methodName = point.getSignature().getName();
        if (rateLimit.limitType() == LimitType.IP) {
            sb.append(IpUtils.getIpAddress(ServletUtils.getRequest())).append("-");
        }
        sb.append(className).append("-").append(methodName);
        return sb.toString();
    }


    private boolean isLimited(String key, int time, int count) {
        // 使用 Redis 的计数器实现限流
        try {
            Long currentCount = redisTemplate.opsForValue().increment(key, 1);
            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, currentCount, key);
            // 如果是第一次访问，设置过期时间
            if (currentCount == 1) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return currentCount > count;
        } catch (Exception e) {
            log.error("限流异常", e);
            return false;
        }
    }
}
